package cn.zebra.dev.mall.module.cart.controller;

import cn.zebra.dev.common.restful.Result;
import cn.zebra.dev.common.utils.DateUtils;
import cn.zebra.dev.mall.module.cart.dto.CartListDTO;
import cn.zebra.dev.mall.module.cart.vo.CartAddVO;
import cn.zebra.dev.mall.module.cart.vo.CartSubmitVO;
import cn.zebra.dev.mall.module.cart.vo.DeleteCartVO;
import cn.zebra.dev.mall.module.cart.vo.UpdateNumVO;
import cn.zebra.dev.member.module.login.service.SecurityMemberService;
import cn.zebra.dev.order.module.item.entity.OrdersItemEntity;
import cn.zebra.dev.order.module.item.service.OrdersItemService;
import cn.zebra.dev.order.module.order.constant.OrdersStatusConstant;
import cn.zebra.dev.order.module.order.constant.OrdersTypeConstant;
import cn.zebra.dev.order.module.order.entity.OrdersEntity;
import cn.zebra.dev.order.module.order.service.OrdersService;
import cn.zebra.dev.product.module.cart.entity.CartEntity;
import cn.zebra.dev.product.module.cart.service.CartService;
import cn.zebra.dev.product.module.product.entity.ProductEntity;
import cn.zebra.dev.product.module.product.service.ProductService;
import cn.zebra.dev.product.module.sku.service.ProductSkuService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author runnable@sina.cn
 */
@Api(tags = "购物车服务")
@RestController
@RequestMapping("/cart")
public class CartController {

    @Autowired
    private SecurityMemberService memberService;

    @Autowired
    private ProductService productService;

    @Autowired
    private OrdersService orderService;

    @Autowired
    private OrdersItemService orderItemService;

    @Autowired
    private ProductSkuService productSkuService;

    @Autowired
    private CartService cartService;

    @PostMapping("/add")
    @ApiOperation("添加到购物车")
    public Result add(@Valid @RequestBody CartAddVO params) {
        Long memberId = memberService.getMemberId();
        Long productId = params.getProductId();
        Long productSkuId = params.getProductSkuId();
        Long num = params.getNum();
        BigDecimal unitPrice = productSkuService.findUnitPriceByProductSkuId(productSkuId);
        CartEntity entity = cartService.findByUserIdAndProductIdAndProductSkuId(memberId, productId, productSkuId);
        if (entity == null) {
            entity = new CartEntity();
            entity.setProductId(productId);
            entity.setUserId(memberId);
            entity.setProductSkuId(productSkuId);
            entity.setUnitPrice(unitPrice);
            entity.setNum(num);
            entity.setTotalPrice(unitPrice);
            entity.setBuyFlag(false);
            entity.setDeleteFlag(false);
            entity.setCreateTime(LocalDateTime.now());
            if (!cartService.save(entity)) {
                return Result.error("添加失败!");
            }
        } else {
            if (!cartService.setNum(entity.getId(), entity.getNum() + num, memberId)) {
                return Result.error("添加失败!");
            }
        }

        return Result.success("添加成功!");
    }

    @GetMapping("/list")
    @ApiOperation("购物车列表内容")
    public Result<Collection<CartListDTO>> list() {
        Collection<CartEntity> list = cartService.list(memberService.getMemberId());
        LinkedList<CartListDTO> dtoList = new LinkedList<>();
        list.forEach(entity -> {
            CartListDTO dto = new CartListDTO();
            BeanUtils.copyProperties(entity, dto);
            dtoList.add(dto);
        });
        return Result.success(dtoList);
    }

    @PostMapping("/submit")
    @ApiOperation("提交订单/结算/生成订单")
    @Transactional(rollbackFor = Exception.class)
    public Result submit(@Valid @RequestBody CartSubmitVO params) {
        Set<Long> cartIds = params.getCartIds();
        Long memberId = memberService.getMemberId();
        Collection<CartEntity> carts = cartService.findByIds(cartIds);
        if (carts.size() != cartIds.size()) {
            return Result.error("购物车列表不匹配!");
        }
        if (carts.stream().anyMatch(CartEntity::getBuyFlag)) {
            return Result.error("请重新刷新购物车!购物车中存在商品已下单!");
        }

        List<Long> productIds = carts.stream().map(CartEntity::getProductId).collect(Collectors.toList());
        List<ProductEntity> productEntities = productService.findByIds(productIds);
        List<OrdersItemEntity> orderItemEntities = new ArrayList<>(carts.size());
        //商家id集合
        Set<Long> shopIds = new HashSet<>();
        BigDecimal totalPrice = BigDecimal.ZERO;
        long totalPoint = 0L;
        long totalNum = 0L;
        for (CartEntity cart : carts) {
            OrdersItemEntity itemEntity = new OrdersItemEntity();
            Long productId = cart.getProductId();
            String productName = cart.getProductName();
            Long num = cart.getNum();
            Optional<ProductEntity> optional = productEntities.stream().filter(product -> product.getId().equals(productId)).findAny();
            if (optional.isPresent()) {
                ProductEntity productEntity = optional.get();
                long point = productEntity.getPoint() * num;
                totalPoint += point;
                itemEntity.setPoint(point);
            } else {
                return Result.error(String.format("%s不存在!", productName));
            }
            Long shopId = cart.getShopId();
            shopIds.add(shopId);
            itemEntity.setShopId(shopId);
            itemEntity.setCartId(cart.getId());
            itemEntity.setProductId(productId);
            itemEntity.setProductName(productName);
            itemEntity.setProductAttributes(cart.getProductAttributes());
            itemEntity.setProductSkuId(cart.getProductSkuId());
            totalNum += num;
            itemEntity.setNum(num);
            itemEntity.setUnitPrice(cart.getUnitPrice());
            BigDecimal itemTotalPrice = cart.getTotalPrice();
            totalPrice = totalPrice.add(itemTotalPrice);
            itemEntity.setTotalPrice(itemTotalPrice);
            itemEntity.setReturnPoint(0L);
            orderItemEntities.add(itemEntity);
            cart.setBuyFlag(true);
        }
        if (!cartService.updateBatchById(carts)) {
            throw new RuntimeException("购物车清理失败!");
        }
        //建立父订单
        OrdersEntity order = new OrdersEntity();
        order.setParentId(0L);
        order.setOrdersSn(System.currentTimeMillis());
        order.setAddressId(0L);
        order.setOrdersType(OrdersTypeConstant.GENERAL);
        order.setOrdersUserId(memberId);
        order.setOrdersTitle("");
        order.setTotalPrice(totalPrice);
        order.setTotalPoint(totalPoint);
        order.setTotalNum(totalNum);
        order.setRemark("");
        order.setOrdersStatus(OrdersStatusConstant.PENDING_PAYMENT);
        order.setCreateTime(LocalDateTime.now());
        order.setPayTime(DateUtils.defaultTime());
        order.setFulfilTime(DateUtils.defaultTime());
        order.setCancelTime(DateUtils.defaultTime());
        order.setOtherTime(DateUtils.defaultTime());
        order.setDeleteFlag(false);
        order.setShopId(0L);
        if (!orderService.save(order)) {
            throw new RuntimeException("下单失败!");
        }
        //顶级订单
        Long orderId = order.getId();
        //判断是否需要拆单 如果商家大于1家则需要拆分订单并分开保存订单明细 上面的订单作为parent订单
        if (shopIds.size() > 1) {
            order.setParentId(orderId);
            for (Long shopId : shopIds) {
                order.setShopId(shopId);
                order.setOrdersSn(System.currentTimeMillis());
                List<OrdersItemEntity> items = orderItemEntities.stream().filter(itemEntity -> itemEntity.getShopId().equals(shopId)).collect(Collectors.toList());
                totalPrice = BigDecimal.ZERO;
                for (OrdersItemEntity itemEntity : items) {
                    totalPrice = totalPrice.add(itemEntity.getTotalPrice());
                }
                order.setTotalPrice(totalPrice);
                totalPoint = 0;
                for (OrdersItemEntity itemEntity : items) {
                    totalPoint += itemEntity.getPoint();
                }
                order.setTotalPoint(totalPoint);
                totalNum = 0;
                for (OrdersItemEntity itemEntity : items) {
                    totalNum += itemEntity.getNum();
                }
                order.setTotalNum(totalNum);
                if (!orderService.save(order)) {
                    throw new RuntimeException("下单失败!");
                }
                //保存至数据库并从集合中移除删除
                items.forEach(itemEntity -> {
                    itemEntity.setOrdersId(order.getId());
                    if (!orderItemService.save(itemEntity)) {
                        throw new RuntimeException("生成订单明细失败!");
                    }
                    orderItemEntities.removeIf(item -> item.getId().equals(itemEntity.getId()));
                });
            }
        }
        orderItemEntities.stream().filter(itemEntity -> itemEntity.getOrdersId() == null).forEach(itemEntity -> itemEntity.setOrdersId(orderId));
        if (!orderItemService.saveBatch(orderItemEntities)) {
            throw new RuntimeException("生成订单明细失败!");
        }
        return Result.success(orderId);
    }

    @PostMapping("/updateNum")
    @ApiOperation("修改购物车指定商品数量")
    public Result updateNum(@Valid @RequestBody UpdateNumVO params) {
        if (cartService.setNum(params.getId(), params.getNum(), memberService.getMemberId())) {
            return Result.success("操作成功!");
        }
        return Result.error("操作失败");
    }

    @GetMapping("/deleteProduct/{id}")
    @ApiOperation("删除购物车指定商品")
    public Result deleteProduct(@PathVariable Long id) {
        if (cartService.deleteCart(id, memberService.getMemberId())) {
            return Result.success("删除成功!");
        }
        return Result.error("删除失败!");
    }

    @PostMapping("/deleteProduct")
    @ApiOperation("删除购物车指定多个商品")
    public Result deleteProduct(@Valid @RequestBody DeleteCartVO params) {
        if (cartService.deleteCart(params.getCartIds(), memberService.getMemberId())) {
            return Result.success("删除成功!");
        }
        return Result.error("删除失败!");
    }
}
